"""
    用于socket连接的多线程程序
    简易的p2p模式,服务端压力和客户端接近
"""
import json
import socket
import threading

from PyPixelCore.util.socket.PyPixelSocketException import PyPixelSocketException
from PyPixelCore.util.socket.PyPixelMessage import PyPixelMessage, message_type


# client________________________________________________________________________________________________________________\
# message_dict(共享的存储信息,在外部创建与维护): "stop" "show_message_block" "client_socket" "message"

def create_client_socket(server_host, server_port, name,message_dict , show_message_block):
    # 首次链接,返回套接字,根据需求
    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try:
        client_socket.connect((server_host, server_port))
        message_dict["client_socket"] = client_socket
        message_dict["message"] = []
        send_message_dict = {'message_type': "link_test", "message_content": f"link-{server_host} | {server_port}", "send_user":name,"receive_user": None}
        message_json = json.dumps(send_message_dict)
        client_socket.sendall(message_json.encode())

        # 创建一个线程来监听服务端消息
        message_dict["show_message_block"] = show_message_block
        client_thread = threading.Thread(target=socket_client_get_message, args=(message_dict, client_socket))
        client_thread.start()
    except:
        client_socket.close() if client_socket else None
        return None
    return client_socket

def send_message_to_server(client_socket, message: PyPixelMessage, message_dict):
    if message_dict["stop"]: return
    try:
        # 整理信息并发送
        send_message_dict = {'message_type': message.message_type, "message_content": message.message_content, "send_user":message.send_user,"receive_user": message.receive_user}
        if message.message_type == message_type.message_talk:
            message_dict["show_message_block"].add_text(f"->客户端: {message.message_content}\n")
        message_json = json.dumps(send_message_dict)
        client_socket.sendall(message_json.encode())
    except:
        return False
    # 如果发送错误,选择关闭socket
    return True

# 循环监听的子线程
def socket_client_get_message(message_dict, client_socket):
    # socket连接的客户端函数
    try:
        while not message_dict["stop"]:
            print("接收信息!")
            # 接收信息
            data = client_socket.recv(1024)
            print(data)
            if data:
                get_message_dict = json.loads(data)
                message = PyPixelMessage(**get_message_dict)
                if message.message_type == message_type.message_talk:
                    message_dict["show_message_block"].add_text(f"-> 服务端: {message.message_content}\n")
                # 退出
                if message.message_type == message_type.message_exit:
                    message_dict["show_message_block"].add_text(f"-> 服务端关闭\n")
                    close_client_socket(message_dict)
                    raise PyPixelSocketException("服务端关闭")
                message_dict["message"].append(message)
    finally:
        client_socket.close()

def close_client_socket(message_dict):
    print("执行客户端关闭程序")
    if "client_socket" in message_dict:
        client_socket = message_dict["client_socket"]
        send_message_dict = {'message_type': message_type.message_exit, "message_content": None, "send_user": None, "receive_user": None}
        message_json = json.dumps(send_message_dict)
        client_socket.sendall(message_json.encode())
        client_socket.close()
        message_dict["stop"] = True
        message_dict["show_message_block"].add_text(f"-> 客户端关闭\n")
        print("执行客户端关闭程序成功")

# server________________________________________________________________________________________________________________
# message_dict(共享的存储信息,在外部创建与维护): "stop" "client_conn_dict" "show_message_block" "server_socket" "message"

def create_server_socket(host, port, message_dict, show_message_block):
    # 创建服务端socket与一个循环监听的线程
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_socket.bind((host, port))
    server_socket.listen(4)  # 监听队列大小

    # 为message_dict添加元素
    message_dict["message"] = []
    message_dict["client_conn_dict"] = {}
    message_dict["show_message_block"] = show_message_block
    message_dict["server_socket"] = server_socket

    listen_thread = threading.Thread(target=socket_server_get_client,args=(host,port, server_socket, message_dict))
    listen_thread.start()

# 一个循环监听客户端请求连接的子线程
def socket_server_get_client(host, port, server_socket, message_dict):
    message_dict["show_message_block"].add_text(f"->正在监听 {host}:{port}\n")
    try:
        while not message_dict["stop"]:
            conn, addr = server_socket.accept()
            # 首条信息附带了用户信息
            data = conn.recv(1024)
            receive_message_dict = json.loads(data)
            message = PyPixelMessage(**receive_message_dict)
            # 根据首条身份信息接受用户
            link_client_thread = threading.Thread(target=socket_server_get_message, args=(conn, addr, message.send_user, message_dict))
            message_dict["client_conn_dict"][message.send_user] = conn
            link_client_thread.start()
        raise PyPixelSocketException("服务端关闭")
    finally:
        try:
            server_socket.close()
        except:
            pass

# 服务器中单独面向某个客户端的子线程
def socket_server_get_message(connection, address, name, message_dict):
    message_dict["show_message_block"].add_text(f"->新连接: {address}\n")
    try:
        while not message_dict["stop"]:
            data = connection.recv(1024)
            if data:
                receive_message_dict = json.loads(data)
                message = PyPixelMessage(**receive_message_dict)
                if message.is_close:
                    message_dict["show_message_block"].add_text(f"客户端退出连接...\n")
                    del message_dict["client_conn_dict"][name]
                    raise PyPixelSocketException("客户端主动退出")
                elif message.message_type == message_type.message_talk:
                    message_dict["show_message_block"].add_text(f"->{name}: {message.message_content}\n")
                message_dict["message"].append(message)
    finally:
        connection.close()

def send_message_to_client(message_dict,message: PyPixelMessage):
    if message_dict["stop"]: return
    if not message.receive_user in message_dict["client_conn_dict"]:
        message_dict["show_message_block"].add_text(f"->当前不存在可发送的客户端连接\n")
        return
    connection = message_dict["client_conn_dict"][message.receive_user]
    try:
        send_message_dict = {'message_type': message.message_type, "message_content": message.message_content, "send_user": message.send_user,
                        "receive_user": message.receive_user}
        if message.message_type == message_type.message_talk:
            message_dict["show_message_block"].add_text(f"-> 服务端: {message.message_content}\n")
        message_json = json.dumps(send_message_dict)
        connection.sendall(message_json.encode())
    except:
        print("发送数据错误")

def close_server_socket(message_dict):
    print("执行服务器端关闭程序")
    print(message_dict)
    linked_user_dict = message_dict["client_conn_dict"]
    if linked_user_dict is not None:
        print( f"linked_user_dict: {linked_user_dict}")
        for each_user_socket in linked_user_dict.values():
            print("给一个用户关闭多线程")
            send_message_dict = {'message_type': message_type.message_exit, "message_content": None, "send_user": None,
                            "receive_user": None}
            message_json = json.dumps(send_message_dict)
            each_user_socket.sendall(message_json.encode())
    message_dict["server_socket"].close()
    message_dict["stop"] = True
    message_dict["show_message_block"].add_text(f"-> 关闭服务端\n")


